namespace Cik.Gapi4Net.Service.Impls
{
    using System;
    using System.Diagnostics;
    using System.Diagnostics.Contracts;
    using Contracts;
    using Core.AcsynRequest;
    using Core.Constant;
    using Core.Exceptions;
    using Domain.Input;
    using Domain.Input.UrlBuilder;
    using Domain.Output.PatentSearch;
    using Entlib.Logging;
    using FluentValidation;
    using Microsoft.Practices.EnterpriseLibrary.Logging;

    internal class PatentSearchService : ServiceBase, IPatentSearchService
    {
        private readonly IUrlBuilder<Patent> _urlBuilder;
        private readonly IValidator<Patent> _validator;

        public PatentSearchService()
        {
        }

        public PatentSearchService(ILoggerFactory loggerFactory, IDownloader downloader, IUrlBuilder<Patent> urlBuilder, IValidator<Patent> validator)
            : base(loggerFactory, downloader)
        {
            _urlBuilder = urlBuilder;
            _validator = validator;
        }

        public PatentSearchResult Search(Func<Patent> func)
        {
            Contract.Assert(_downloader != null, "Downloader is null");
            Contract.Assert(_logger != null, "Logger is null");
            Contract.Assert(_urlBuilder != null, "UrlBuilder is null");
            Contract.Assert(_validator != null, "PatentValidator is null");

            try
            {
                // call the function for get the real entity
                var patent = func();

                // validator this entity
                _validator.ValidateAndThrow(patent);

                _urlBuilder.Entity = patent;
                var result = _urlBuilder.BuildUrl();

                var searchUrl = CommonConstant.PatentSearchUrl + result;

                return GetResultData<PatentSearchResult>(searchUrl);
            }
            catch (Exception ex)
            {
                var logEntry = new LogEntry(ex.Message, "GApi4Net", 1, 0, TraceEventType.Error, "GApi4Net", null);
                _logger.Write(logEntry);

                throw new PatentSearchException(ex.Message);
            }
        }

        public PatentSearchResult Search(string version, string query)
        {
            Contract.Assert(_downloader != null, "Downloader is null");
            Contract.Assert(_logger != null, "Logger is null");

            try
            {
                var webSearch = new Patent { Version = version, Query = query };

                // validator this entity
                _validator.ValidateAndThrow(webSearch);

                var searchUrl = CommonConstant.PatentSearchUrl + webSearch.SearchWebUrl();

                return GetResultData<PatentSearchResult>(searchUrl);
            }
            catch (Exception ex)
            {
                var logEntry = new LogEntry(ex.Message, "GApi4Net", 1, 0, TraceEventType.Error, "GApi4Net", null);
                _logger.Write(logEntry);

                throw new PatentSearchException(ex.Message);
            }
        }
    }
}